"""K8s资源依赖分析模块"""

from typing import Dict, Any, List, Set, Optional
import logging
from dataclasses import dataclass
from collections import defaultdict

@dataclass
class ResourceReference:
    """资源引用信息"""
    kind: str
    name: str
    namespace: str
    reference_type: str  # 引用类型：selector, volume, env, etc.

@dataclass
class DependencyInfo:
    """依赖关系信息"""
    resource_type: str
    resource_name: str
    namespace: str
    dependencies: List[ResourceReference]
    dependents: List[ResourceReference]

class ResourceDependencyAnalyzer:
    """K8s资源依赖分析器"""
    
    def __init__(self, logger: Optional[logging.Logger] = None):
        self.logger = logger or logging.getLogger(__name__)
        self.resources: Dict[str, Dict[str, Any]] = {}  # 存储所有资源
        self.dependencies: Dict[str, DependencyInfo] = {}  # 存储依赖关系
    
    def add_resource(self, resource_type: str, name: str, namespace: str, content: Dict[str, Any]) -> None:
        """
        添加资源到分析器
        
        Args:
            resource_type: 资源类型
            name: 资源名称
            namespace: 命名空间
            content: 资源内容
        """
        key = f"{namespace}/{resource_type}/{name}"
        self.resources[key] = content
        self.dependencies[key] = DependencyInfo(
            resource_type=resource_type,
            resource_name=name,
            namespace=namespace,
            dependencies=[],
            dependents=[]
        )
    
    def analyze_dependencies(self) -> None:
        """分析所有资源的依赖关系"""
        for key, content in self.resources.items():
            namespace, resource_type, name = key.split('/')
            self._analyze_resource_dependencies(key, resource_type, content)
    
    def _analyze_resource_dependencies(self, key: str, resource_type: str, content: Dict[str, Any]) -> None:
        """
        分析单个资源的依赖关系
        
        Args:
            key: 资源键
            resource_type: 资源类型
            content: 资源内容
        """
        if resource_type == "Deployment":
            self._analyze_deployment_dependencies(key, content)
        elif resource_type == "StatefulSet":
            self._analyze_statefulset_dependencies(key, content)
        elif resource_type == "Service":
            self._analyze_service_dependencies(key, content)
        elif resource_type == "Pod":
            self._analyze_pod_dependencies(key, content)
        elif resource_type == "ConfigMap":
            self._analyze_configmap_dependencies(key, content)
        elif resource_type == "Secret":
            self._analyze_secret_dependencies(key, content)
    
    def _analyze_deployment_dependencies(self, key: str, content: Dict[str, Any]) -> None:
        """分析Deployment的依赖关系"""
        namespace = self.dependencies[key].namespace
        spec = content.get("spec", {})
        template = spec.get("template", {})
        
        # 分析Pod模板中的依赖
        self._analyze_pod_template_dependencies(key, template, namespace)
    
    def _analyze_statefulset_dependencies(self, key: str, content: Dict[str, Any]) -> None:
        """分析StatefulSet的依赖关系"""
        namespace = self.dependencies[key].namespace
        spec = content.get("spec", {})
        template = spec.get("template", {})
        
        # 分析Pod模板中的依赖
        self._analyze_pod_template_dependencies(key, template, namespace)
        
        # 分析卷声明
        volume_claim_templates = spec.get("volumeClaimTemplates", [])
        for vct in volume_claim_templates:
            self._add_dependency(
                key,
                "PersistentVolumeClaim",
                vct.get("metadata", {}).get("name", ""),
                namespace,
                "volume_claim"
            )
    
    def _analyze_service_dependencies(self, key: str, content: Dict[str, Any]) -> None:
        """分析Service的依赖关系"""
        namespace = self.dependencies[key].namespace
        spec = content.get("spec", {})
        
        # 分析选择器
        selector = spec.get("selector", {})
        if selector:
            # 查找匹配的Pod
            for pod_key, pod_content in self.resources.items():
                if pod_key.startswith(f"{namespace}/Pod/"):
                    pod_labels = pod_content.get("metadata", {}).get("labels", {})
                    if all(pod_labels.get(k) == v for k, v in selector.items()):
                        self._add_dependency(key, "Pod", pod_key.split('/')[-1], namespace, "selector")
    
    def _analyze_pod_dependencies(self, key: str, content: Dict[str, Any]) -> None:
        """分析Pod的依赖关系"""
        namespace = self.dependencies[key].namespace
        spec = content.get("spec", {})
        
        # 分析卷
        volumes = spec.get("volumes", [])
        for volume in volumes:
            # 检查ConfigMap卷
            config_map = volume.get("configMap", {})
            if config_map:
                self._add_dependency(
                    key,
                    "ConfigMap",
                    config_map.get("name", ""),
                    namespace,
                    "volume"
                )
            
            # 检查Secret卷
            secret = volume.get("secret", {})
            if secret:
                self._add_dependency(
                    key,
                    "Secret",
                    secret.get("secretName", ""),
                    namespace,
                    "volume"
                )
        
        # 分析容器
        containers = spec.get("containers", [])
        for container in containers:
            # 分析环境变量
            env = container.get("env", [])
            for env_var in env:
                # 检查ConfigMap引用
                value_from = env_var.get("valueFrom", {})
                config_map_key_ref = value_from.get("configMapKeyRef", {})
                if config_map_key_ref:
                    self._add_dependency(
                        key,
                        "ConfigMap",
                        config_map_key_ref.get("name", ""),
                        namespace,
                        "env"
                    )
                
                # 检查Secret引用
                secret_key_ref = value_from.get("secretKeyRef", {})
                if secret_key_ref:
                    self._add_dependency(
                        key,
                        "Secret",
                        secret_key_ref.get("name", ""),
                        namespace,
                        "env"
                    )
    
    def _analyze_pod_template_dependencies(self, key: str, template: Dict[str, Any], namespace: str) -> None:
        """分析Pod模板中的依赖关系"""
        spec = template.get("spec", {})
        
        # 分析卷
        volumes = spec.get("volumes", [])
        for volume in volumes:
            # 检查ConfigMap卷
            config_map = volume.get("configMap", {})
            if config_map:
                self._add_dependency(
                    key,
                    "ConfigMap",
                    config_map.get("name", ""),
                    namespace,
                    "volume"
                )
            
            # 检查Secret卷
            secret = volume.get("secret", {})
            if secret:
                self._add_dependency(
                    key,
                    "Secret",
                    secret.get("secretName", ""),
                    namespace,
                    "volume"
                )
        
        # 分析容器
        containers = spec.get("containers", [])
        for container in containers:
            # 分析环境变量
            env = container.get("env", [])
            for env_var in env:
                # 检查ConfigMap引用
                value_from = env_var.get("valueFrom", {})
                config_map_key_ref = value_from.get("configMapKeyRef", {})
                if config_map_key_ref:
                    self._add_dependency(
                        key,
                        "ConfigMap",
                        config_map_key_ref.get("name", ""),
                        namespace,
                        "env"
                    )
                
                # 检查Secret引用
                secret_key_ref = value_from.get("secretKeyRef", {})
                if secret_key_ref:
                    self._add_dependency(
                        key,
                        "Secret",
                        secret_key_ref.get("name", ""),
                        namespace,
                        "env"
                    )
    
    def _analyze_configmap_dependencies(self, key: str, content: Dict[str, Any]) -> None:
        """分析ConfigMap的依赖关系"""
        # ConfigMap通常是被依赖的资源，不需要分析其依赖
        pass
    
    def _analyze_secret_dependencies(self, key: str, content: Dict[str, Any]) -> None:
        """分析Secret的依赖关系"""
        # Secret通常是被依赖的资源，不需要分析其依赖
        pass
    
    def _add_dependency(self, source_key: str, target_kind: str, target_name: str, namespace: str, ref_type: str) -> None:
        """
        添加依赖关系
        
        Args:
            source_key: 源资源键
            target_kind: 目标资源类型
            target_name: 目标资源名称
            namespace: 命名空间
            ref_type: 引用类型
        """
        if not target_name:
            return
        
        target_key = f"{namespace}/{target_kind}/{target_name}"
        
        # 添加依赖关系
        if source_key in self.dependencies:
            self.dependencies[source_key].dependencies.append(
                ResourceReference(
                    kind=target_kind,
                    name=target_name,
                    namespace=namespace,
                    reference_type=ref_type
                )
            )
        
        # 添加被依赖关系
        if target_key in self.dependencies:
            self.dependencies[target_key].dependents.append(
                ResourceReference(
                    kind=self.dependencies[source_key].resource_type,
                    name=self.dependencies[source_key].resource_name,
                    namespace=self.dependencies[source_key].namespace,
                    reference_type=ref_type
                )
            )
    
    def get_dependencies(self, resource_type: str, name: str, namespace: str) -> Optional[DependencyInfo]:
        """
        获取资源的依赖关系
        
        Args:
            resource_type: 资源类型
            name: 资源名称
            namespace: 命名空间
            
        Returns:
            依赖关系信息
        """
        key = f"{namespace}/{resource_type}/{name}"
        return self.dependencies.get(key)
    
    def get_all_dependencies(self) -> Dict[str, DependencyInfo]:
        """
        获取所有资源的依赖关系
        
        Returns:
            所有资源的依赖关系信息
        """
        return self.dependencies
    
    def export_dependency_graph(self, output_path: str) -> None:
        """
        导出依赖关系图
        
        Args:
            output_path: 输出文件路径
        """
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write("K8s资源依赖关系图\n")
                f.write("=" * 50 + "\n\n")
                
                for key, info in self.dependencies.items():
                    f.write(f"资源: {info.resource_type}/{info.resource_name} (命名空间: {info.namespace})\n")
                    f.write("-" * 50 + "\n")
                    
                    # 输出依赖
                    if info.dependencies:
                        f.write("\n依赖的资源:\n")
                        for dep in info.dependencies:
                            f.write(f"  - {dep.kind}/{dep.name} ({dep.reference_type})\n")
                    
                    # 输出被依赖
                    if info.dependents:
                        f.write("\n被以下资源依赖:\n")
                        for dep in info.dependents:
                            f.write(f"  - {dep.kind}/{dep.name} ({dep.reference_type})\n")
                    
                    f.write("\n" + "=" * 50 + "\n\n")
            
            self.logger.info(f"依赖关系图已导出到: {output_path}")
        except Exception as e:
            self.logger.error(f"导出依赖关系图失败: {str(e)}")
            raise 